#include "Lily_help.h"
#include <math.h>
#include "hashlib.h"

char rx[256];
unsigned char ri, hi;
int32_t _cmd_queue_in_waiting = 0;
int32_t _lily_is_busy = 0;
LilyUI_t lily_ui = {.cmds = NULL, .funs = NULL, .vars = NULL, .hijacker_callback = NULL, ._cmd_done_listener = NULL, .open_time = 0, .lily_std_pipe = NULL, ._error_msg = NULL};

static Cmdline_def ui_stack[lily_do_stack_len];
char _stack_top = 0;

Tasks_def _cmd_done_listener[lily_do_stack_len];
char _cmd_done_listener_stack_top = 0;
#define max_cmd_len 127
void freeze_cmd_stream()
{
	_lily_is_busy = 1;
}
void resume_cmd_stream()
{
	_lily_is_busy = 0;
	if (_cmd_queue_in_waiting)
		tp_addTask(_get_cmd_from_rx);
}

int32_t _get_cmd_from_rx()
{
	static char cmd[max_cmd_len + 1];

	if (_lily_is_busy)
	{
		return 0;
	}
	if (hi == ri)
	{
		_cmd_queue_in_waiting = 0;
		return 0;
	}
	int32_t i = 0;
	char c;
	for (; rx[hi] != '\0' && i < max_cmd_len; i++, hi++)
	{
		c = rx[hi];
		cmd[i] = c;
	}
	if (i >= max_cmd_len)
	{
		while (rx[hi] != '\0')
		{
			hi++;
		}
	}

#ifdef in_debug
	if (i >= max_cmd_len)
		lily_out("cmd too long\n");
#endif

	cmd[i] = '\0';
	hi++;
	lily_do(cmd);
	if (hi == ri)
	{
		_cmd_queue_in_waiting = 0;
		return 0;
	}
	if (--_cmd_queue_in_waiting)
		return 1;
	return 0;
}

int32_t lily_do(char *rx)
{
	char tx[TX_len];
	uint32_t t = _li_millis();
	while (t < lily_ui.open_time)
	{
		_li_Delay(1);
		t = _li_millis();
	}

#ifdef in_debug
	if (rx == NULL)
	{
		lily_out("shell do error");
		li_error("null ptr", -__LINE__);
	}
#endif

	if (_stack_top)
	{

		int32_t return_code = ui_stack[(int32_t)_stack_top](1, &rx);
		if (!(return_code & KeepHijack))
		{
			if (_stack_top)
				_stack_top--;
		}
		if (!(return_code & Lily_cmd_do_not_notify))
		{
			if (have_listener)
			{
				tp_addTask(current_listener);
			}
		}
		return 0;
	}

	rx += str_left_wrap(rx, ' ');
	Pipe lily_out_backup = lily_get_current_pipe();
	__li_error_msg2 = __li_error_msg;
	__li_error_msg = NULL;
	if (*rx == '\0')
	{
		if (have_listener)
			tp_addTask(current_listener);
		return 0;
	}
	int32_t redir_ind = _test_redirection_output_to_var(rx);

	int32_t code = 0;
	typedef int32_t (*shell_do_def)(char *);

	const shell_do_def shell_do[] = {shell_do_fun, shell_do_cmd, shell_do_cal, shell_do_var, shell_do_notFound};
	char rx_back[max_cmd_len + 1];
	int32_t i;

	if (*rx == '$')
	{
		rx++;
		int32_t ind_c = search_cmd_in_Lily_ui("set");
		if (ind_c >= 0)
		{
			Cmd _cmd = li_cmds + ind_c;
			char *_args[2] = {NULL, rx};
			_cmd->todo(2, _args);
		}
	}
	else if (*rx != '#')
	{
		for (i = 0; i < 5; i++)
		{
			strcpy(rx_back, rx);
			code = (shell_do[i])(rx_back);
			if (code == 0)
				continue;
			break;
		}
	}
	if (code < 0)
	{
		lily_out(rx);
		sprintf(tx, "\a\nerror(%d):", code);
		lily_out(tx);
		if (__li_error_msg != NULL)
			lily_out((char *)__li_error_msg);
		lily_out("\n");
	}
	if (have_listener)
	{
		if (code < 0 || !(code & Lily_cmd_do_not_notify))
		{
			tp_addTask(current_listener);
		}
	}
	if (!__li_error_msg)
		__li_error_msg = __li_error_msg2;
	if (redir_ind > 0)
	{
		lily_redirect_output(lily_out_backup);
		rx[redir_ind] = '>';
	}
	return 0;
}

void add_hijack(Cmdline_def call_back)
{
	ui_stack[(int32_t)(++_stack_top)] = call_back;
	// lily_ui.hijacked = 1;
	if (_stack_top >= lily_do_stack_len)
	{
		lily_out(">>ui stack overflow!");
		_stack_top = 0;
		// lily_ui.hijacked = 0;
	}
}

void add_listener(Tasks_def f)
{
	_cmd_done_listener[cast(_cmd_done_listener_stack_top++, int32_t)] = f;
	if (_cmd_done_listener_stack_top >= lily_do_stack_len)
	{
		lily_out(">>listener stack overflow!");
		_cmd_done_listener_stack_top = 0;
	}
}

int32_t notify_listener()
{
	if (have_listener)
	{
		tp_addTask(current_listener);
		return 1;
	}
	return 0;
}

// @deprecated
int32_t joint_args(int32_t n, char **args)
{
	int32_t i;
	char *p;
	n = n - 1;
	int32_t len = 0;
	for (i = 0; i < n; i++)
	{
		int32_t nn = strlen(args[i]);
		p = args[i] + nn;
		len += nn;
		*p = ' ';
	}
	return len;
}
